import os

# 定义棋盘的行和列
SIZE = 23
# 定义玩家和电脑的棋子
player_chess = '*'
computer_chess = 'O'


def game():
    iswin = 0
    # 生成棋盘和评分表
    board = [[0 for _ in range(SIZE)] for _ in range(SIZE)]
    mark_sheet = [[0 for _ in range(SIZE)] for _ in range(SIZE)]
    InitBoard(board, SIZE)                      # 初始化棋盘
    display_board(board, SIZE)                  # 展示棋盘
    while True:
        chess_player(board, SIZE)               # 玩家落子
        os.system('cls')                        # 清屏
        display_board(board, SIZE)
        iswin = check_winner(board, SIZE)       # 判断当前是否有人胜利
        if iswin:
            print("恭喜你赢了！！！")
            break
        chess_computer(board, mark_sheet, SIZE) # 电脑落子
        os.system('cls')
        display_board(board, SIZE)
        iswin = check_winner(board, SIZE)
        if iswin:
            print("很遗憾你输了！！！")
            break

# 打印菜单
def menu():
    print("======== 五子棋游戏 ========")
    print("======== 1.开始游戏 ========")
    print("======== 2.退出游戏 ========")
    print("请输入相应的数字以进行相应选择：")

# 初始化数组
def InitBoard(board: list, size: int):
    for i in range(size):
        for j in range(size):
            board[i][j] = ' '  # 使用空格表示空白棋盘格

# 打印棋盘
def display_board(board, size):
    row = 0
    # 打印上边界的坐标
    print(" ", end="")
    for i in range(4, size - 4):
        if i <= 12:
            print(f" {i - 3}  ", end="")
        else:
            print(f" {i - 3} ", end="")
    print()

    for i in range(4, size - 4):
        print("------------" * 5)
        for j in range(4, size - 4):
            print(f"| {board[i][j]} ", end="")
            if j == size - 4 - 1:
                row += 1
                print(f"|{row} ")
                break
    print("------------" * 5)
    print(f"玩家使用 {player_chess}, 电脑使用 {computer_chess}。请输入您想放置棋子的行和列（例如：3 4）：")

# 玩家落子
def chess_player(board: list, size: int):
    while True:
        input_coords = input("请输入行和列（例如：3 5）：")
        try:
            x, y = map(int, input_coords.split())
        except ValueError:
            print("输入无效，请输入两个整数，用空格分隔！")
            continue

        x += 4  # 调整到棋盘的有效范围
        y += 4

        if 4 < x <= size - 4 and 4 < y <= size - 4 and board[x-1][y-1] == ' ':
            board[x-1][y-1] = player_chess
            break
        else:
            print("输入无效，该位置已被占用或超出棋盘范围，请重新输入！")

# 检查是否有人胜利
def check_winner(board:list, size:int):
    for i in range(4, size - 4):
        for j in range(4, size - 4):
            player = board[i][j]
            # 检查水平方向
            if player != ' ' and all(board[i][k] == player for k in range(j, j + 5)):
                return 1
            # 检查垂直方向
            if player != ' ' and all(board[k][j] == player for k in range(i, i + 5)):
                return 1
            # 检查正斜对角线方向
            if player != ' ' and all(board[i + m][j + m] == player for m in range(1, 5)):
                return 1
            # 检查反斜对角线方向
            if player != ' ' and all(board[i + m][j - m] == player for m in range(1, 5)):
                return 1
    return 0  # 没有五个连续相同的棋子

# 电脑落子
def chess_computer(board:list, mark_sheet:list, size:int):
    max_grade = -999

    # Mark_Sheet用于更新评分表
    Mark_Sheet(board, mark_sheet, size)

    for i in range(size):
        for j in range(size):
            if mark_sheet[i][j] > max_grade:
                max_grade = mark_sheet[i][j]
                x, y = i, j

    board[x][y] = computer_chess

# 其他函数的实现
# 对棋盘上的一个落子点进行评分
def Grade(board: list, size: int, x: int, y: int):
    # 检查是否是非法落子点
    if x < 4 or x >= size - 4 or y < 4 or y >= size - 4 or board[x][y] != ' ':
        return -999  # 如果是非法点，则扣分

    # 连五子和堵四子优先执行
    chess = [computer_chess, player_chess]
    for ch in chess:
        board[x][y] = ch
        if check_winner(board, size):
            board[x][y] = ' '
            return 999
        else:
            board[x][y] = ' '

    grade = 0
    flag = 0

    # 检查落子点是否太过于偏远
    # 检查周围一圈是否都没有棋子
    for i in range(-1, 2):
        for j in range(-1, 2):
            if board[x + i][y + j] != ' ' and i != 0 and j != 0:
                flag = 1
                break
        if flag:
            break
    if flag == 0:
        grade -= 1
    # 检查周围一圈是否都没有对方棋子
    for i in range(-1, 2):
        for j in range(-1, 2):
            if board[x + i][y + j] == player_chess and i != 0 and j != 0:
                flag = 1
                break
        if flag:
            break
    if flag == 0:
        grade -= 1

    # 检查落子点是否处于地图边界
    if (4 < x <= 6 or size - 6 < x <=size - 4) and (4 < y <= 6 or size - 6 < y <=size - 4):
        grade -= 3
    if (4 < x <= 6 or size - 6 < x <=size - 4) or (4 < y <= 6 or size - 6 < y <=size - 4):
        grade -= 2

    # 电脑的防守与进攻
    flag = 1 # 避免了连四子和连三子的分数累加到一块
    count = 0 # 用于接收可以一次性连成几个的四子，三子，堵住几个的三子

    # 可连四子
    count = count4(board, size, x, y, computer_chess)
    if count:
        flag = 0
        grade += 8*count
    # 可连三子
    count = count3(board, size, x, y, computer_chess)
    if count and flag:
        grade += 4*count

    flag = 1
    # 可堵三子
    count = count4(board, size, x, y, player_chess)
    if count:
        flag = 0
        grade += 8*count
    # 可堵二子
    count = count3(board, size, x, y, player_chess)
    if count and flag:
        grade += 4*count

    return grade

# 更新评分表，将每个点的分值记录下来
def Mark_Sheet(board:list, mark_sheet:list, size:int):
    for i in range(size):
        for j in range(size):
            mark_sheet[i][j] = Grade(board, size, i, j)


# count4,count3 函数的实现
# 检查可连成四子的情况，如果连成的是活四子，则得分更高，如果是死四子，则得分相对较少
def count4(board:list, size:int, x:int, y:int, chess_type):
    count = 0
    # 检查水平方向
    judge = [0] # 为了使索引和实际对应，我们让judge在初始时就已经含有一个元素
    judge.append(chess_type == board[x + 1][y] == board[x + 2][y] == board[x + 3][y])
    judge.append(chess_type == board[x - 1][y] == board[x + 1][y] == board[x + 2][y])
    judge.append(chess_type == board[x - 2][y] == board[x - 1][y] == board[x + 1][y])
    judge.append(chess_type == board[x - 3][y] == board[x - 2][y] == board[x - 1][y])

    judge_useful = [0]
    judge_useful.append(judge[1] and board[x + 4][y] == board[x - 1][y] == ' ')
    judge_useful.append(judge[2] and board[x - 2][y] == board[x + 3][y] == ' ')
    judge_useful.append(judge[3] and board[x - 3][y] == board[x + 2][y] == ' ')
    judge_useful.append(judge[4] and board[x - 4][y] == board[x + 1][y] == ' ')

    flag = 0 # 用作标记，防止活四子和死四子的分数加在一块
    if judge_useful[1] or judge_useful[2] or judge_useful[3] or judge_useful[4]:
        count += 2
        flag = 1
    if judge[1] or judge[2] or judge[3] or judge[4] and flag:
        count += 1

    # 检查竖直方向
    judge = [0]
    judge.append(chess_type == board[x][y + 1] == board[x][y + 2] == board[x][y + 3])
    judge.append(chess_type == board[x][y - 1] == board[x][y + 1] == board[x][y + 2])
    judge.append(chess_type == board[x][y - 2] == board[x][y - 1] == board[x][y + 1])
    judge.append(chess_type == board[x][y - 3] == board[x][y - 2] == board[x][y - 1])

    judge_useful = [0]
    judge_useful.append(judge[1] and board[x][y + 4] == board[x][y - 1] == ' ')
    judge_useful.append(judge[2] and board[x][y - 2] == board[x][y + 3] == ' ')
    judge_useful.append(judge[3] and board[x][y - 3] == board[x][y + 2] == ' ')
    judge_useful.append(judge[4] and board[x][y - 4] == board[x][y + 1] == ' ')

    flag = 0
    if judge_useful[1] or judge_useful[2] or judge_useful[3] or judge_useful[4]:
        count += 2
        flag = 1
    if judge[1] or judge[2] or judge[3] or judge[4] and flag:
        count += 1

    # 检查正对角线方向
    judge = [0]
    judge.append(chess_type == board[x + 1][y + 1] == board[x + 2][y + 2] == board[x + 3][y + 3])
    judge.append(chess_type == board[x - 1][y - 1] == board[x + 1][y + 1] == board[x + 2][y + 2])
    judge.append(chess_type == board[x - 2][y - 2] == board[x - 1][y - 1] == board[x + 1][y + 1])
    judge.append(chess_type == board[x - 3][y - 3] == board[x - 2][y - 2] == board[x - 1][y - 1])

    judge_useful = [0]
    judge_useful.append(judge[1] and board[x + 4][y + 4] == board[x - 1][y - 1] == ' ')
    judge_useful.append(judge[2] and board[x - 2][y - 2] == board[x + 3][y + 3] == ' ')
    judge_useful.append(judge[3] and board[x - 3][y - 3] == board[x + 2][y + 2] == ' ')
    judge_useful.append(judge[4] and board[x - 4][y - 4] == board[x + 1][y + 1] == ' ')

    flag = 0
    if judge_useful[1] or judge_useful[2] or judge_useful[3] or judge_useful[4]:
        count += 2
        flag = 1
    if judge[1] or judge[2] or judge[3] or judge[4] and flag:
        count += 1

    # 检查反对角线方向
    judge = [0]
    judge.append(chess_type == board[x - 1][y + 1] == board[x - 2][y + 2] == board[x - 3][y + 3])
    judge.append(chess_type == board[x + 1][y - 1] == board[x - 1][y + 1] == board[x - 2][y + 2])
    judge.append(chess_type == board[x + 2][y - 2] == board[x + 1][y - 1] == board[x - 1][y + 1])
    judge.append(chess_type == board[x + 3][y - 3] == board[x + 2][y - 2] == board[x + 1][y - 1])

    judge_useful = [0]
    judge_useful.append(judge[1] and board[x - 4][y + 4] == board[x + 1][y - 1] == ' ')
    judge_useful.append(judge[2] and board[x + 2][y - 2] == board[x - 3][y + 3] == ' ')
    judge_useful.append(judge[3] and board[x + 3][y - 3] == board[x - 2][y + 2] == ' ')
    judge_useful.append(judge[4] and board[x + 4][y - 4] == board[x - 1][y + 1] == ' ')

    flag = 0
    if judge_useful[1] or judge_useful[2] or judge_useful[3] or judge_useful[4]:
        count += 2
        flag = 1
    if judge[1] or judge[2] or judge[3] or judge[4] and flag:
        count += 1

    return count


# 检查可连成三子的情况，如果连成的是活三子，则得分更高，如果是死三子，则得分相对较少
def count3(board:list, size:int, x:int, y:int, chess_type):
    count = 0
    # 检查水平方向
    judge = [0]
    judge.append(chess_type == board[x + 1][y] == board[x + 2][y])
    judge.append(chess_type == board[x - 1][y] == board[x + 1][y])
    judge.append(chess_type == board[x - 2][y] == board[x - 1][y])

    judge_useful = [0]
    judge_useful.append(judge[1] and board[x + 3][y] == board[x - 1][y] == ' ')
    judge_useful.append(judge[2] and board[x - 2][y] == board[x + 2][y] == ' ')
    judge_useful.append(judge[3] and board[x - 3][y] == board[x + 1][y] == ' ')

    flag = 0
    if judge_useful[1] or judge_useful[2] or judge_useful[3]:
        count += 2
        flag = 1
    if judge[1] or judge[2] or judge[3] and flag:
        count += 1

    # 检查竖直方向
    judge = [0]
    judge.append(chess_type == board[x][y + 1] == board[x][y + 2])
    judge.append(chess_type == board[x][y - 1] == board[x][y + 1])
    judge.append(chess_type == board[x][y - 2] == board[x][y - 1])

    judge_useful = [0]
    judge_useful.append(judge[1] and board[x][y + 3] == board[x][y - 1] == ' ')
    judge_useful.append(judge[2] and board[x][y - 2] == board[x][y + 2] == ' ')
    judge_useful.append(judge[3] and board[x][y - 3] == board[x][y + 1] == ' ')

    flag = 0
    if judge_useful[1] or judge_useful[2] or judge_useful[3]:
        count += 2
        flag = 1
    if judge[1] or judge[2] or judge[3] and flag:
        count += 1

    # 检查正对角线方向
    judge = [0]
    judge.append(chess_type == board[x + 1][y + 1] == board[x + 2][y + 2])
    judge.append(chess_type == board[x - 1][y - 1] == board[x + 1][y + 1])
    judge.append(chess_type == board[x - 2][y - 2] == board[x - 1][y - 1])

    judge_useful = [0]
    judge_useful.append(judge[1] and board[x + 3][y + 3] == board[x - 1][y - 1] == ' ')
    judge_useful.append(judge[2] and board[x - 2][y - 2] == board[x + 2][y + 2] == ' ')
    judge_useful.append(judge[3] and board[x - 3][y - 3] == board[x + 1][y + 1] == ' ')

    flag = 0
    if judge_useful[1] or judge_useful[2] or judge_useful[3]:
        count += 2
        flag = 1
    if judge[1] or judge[2] or judge[3] and flag:
        count += 1

    # 检查反对角线方向
    judge = [0]
    judge.append(chess_type == board[x - 1][y + 1] == board[x - 2][y + 2])
    judge.append(chess_type == board[x + 1][y - 1] == board[x - 1][y + 1])
    judge.append(chess_type == board[x + 2][y - 2] == board[x + 1][y - 1])

    judge_useful = [0]
    judge_useful.append(judge[1] and board[x - 3][y + 3] == board[x + 1][y - 1] == ' ')
    judge_useful.append(judge[2] and board[x + 2][y - 2] == board[x - 2][y + 2] == ' ')
    judge_useful.append(judge[3] and board[x + 3][y - 3] == board[x - 1][y + 1] == ' ')

    flag = 0
    if judge_useful[1] or judge_useful[2] or judge_useful[3]:
        count += 2
        flag = 1
    if judge[1] or judge[2] or judge[3] and flag:
        count += 1

    return count

# 主函数
choice = 0
while True:
    menu()
    print("请选择是否进行游戏:>>", end = '')
    choice = int(input(""))
    if choice == 1:
        print("五子棋游戏，现在开始！！！")
        game()
    elif choice == 2:
        print("已退出游戏。")
        break
    else:
        print("选择错误，请重新选择！")